from datetime import date

from odoo import fields, models, api, _
from odoo.exceptions import UserError, ValidationError


class ConsignmentSalesLine(models.Model):
    _name = 'consignment.sales.line'
    _description = 'Consignment Sales Line'

    name = fields.Char(string='Name')
    product_id = fields.Many2one('product.template', string='Product', required=True)
    quantity = fields.Float(string='Quantity', default=1)
    consignment_id = fields.Many2one('consignment.sales', string='Consignment Sales',
                                     domain=[('state', 'not in', ['draft'])],
                                     ondelete='cascade',
                                     required=True)
    state = fields.Selection([('hole', 'Hole'),
                              ('sent_out', 'Sent Out'),
                              ('received', 'Received'),
                              ('cancel', 'Cancel'),
                              ('refunded', 'Refunded')]
                             , default='hole'
                             , string='State'
                             , compute='_compute_state', store=True)
    type = fields.Selection([('deliver', 'Deliver'), ('return', 'Return')], string='Type')
    quantity_state = fields.Boolean(string='Quantity State', compute='_compute_quantity_state')
    stock_move_id = fields.Many2one('stock.move', string='Stock Move', ondelete='cascade')
    sp_id = fields.Many2one('stock.picking', string='Stock Picking', related='stock_move_id.picking_id', store=True)

    @api.depends('stock_move_id.state')
    def _compute_state(self):
        for rec in self:
            if rec.state != 'refunded':
                if rec.stock_move_id.state == 'draft':
                    rec.state = 'hole'
                elif rec.stock_move_id.state in ['assigned', 'confirmed', 'partially_available']:
                    rec.state = 'sent_out'
                elif rec.stock_move_id.state == 'done':
                    rec.state = 'received'
                elif rec.stock_move_id.state == 'cancel':
                    rec.state = 'cancel'

    @api.depends('quantity', 'product_id.qty_available')
    def _compute_quantity_state(self):
        for rec in self:
            if rec.quantity > rec.product_id.qty_available:
                rec.quantity_state = False
            else:
                rec.quantity_state = True

    def action_confirm(self):
        for rec in self:
            if not rec.quantity_state:
                raise UserError(_(f"The quantity of product {rec.product_id.name} is {rec.product_id.qty_available}, the stock is insufficient."))
            else:
                self.env['stock.picking'].create({
                    'picking_type_id': self.env.ref('consignment.cs_stock_pick_type').id,
                    'location_id': rec.consignment_id.customer_id.property_stock_customer.id,
                    'location_dest_id': self.env.ref('consignment.cs_stock_location').id,
                    'move_ids_without_package': [(0, 0, {
                        'name': rec.product_id.name,
                        'product_id': rec.product_id.product_variant_ids,
                        'product_uom_qty': rec.quantity,
                    })]
                })
                rec.state = 'sent_out'


class ConsignmentSales(models.Model):
    _name = 'consignment.sales'
    _inherit = ['portal.mixin', 'mail.thread', 'mail.activity.mixin', 'utm.mixin']
    name = fields.Char(string='Name', default='Draft')
    customer_id = fields.Many2one('res.partner', string='Customer')
    set_in_date = fields.Date(string='Set in Date', default=lambda self: date.today())
    done_date = fields.Date(string='Done Date')
    state = fields.Selection([('draft', 'Draft'), ('confirmed', 'Confirmed'), ('done', 'Done')]
                             , default='draft', string='State')
    sc_lines = fields.One2many('consignment.sales.line', 'consignment_id', string='Consignment Sales Lines')
    sp_ids = fields.One2many('stock.picking', 'consignment_id', string='Stock Picking')
    product_id = fields.Many2one('product.template', string='Product')
    unit_price = fields.Float(string='Unit')
    quantity = fields.Float(string='Contract Estimated Qty', digits=([12, 2]))
    qty_shipped = fields.Float(string='Qty Shipped', digits=([12, 2]), compute='_compute_qty_shipped', store=True)
    product_uom_id = fields.Many2one('uom.uom', string='Product UOM', related='product_id.uom_id')
    owe_qty = fields.Float(string='Owe Qty', compute='_compute_owe_qty')
    used_qty = fields.Float(string='Used Qty')
    tax_ids = fields.Many2many('account.tax', string='Taxes', store=True)
    account_move_ids = fields.Many2many('account.move', string='Account Move')
    invoiced_qty = fields.Float(string='Invoiced Qty', compute='_compute_invoiced_qty')

    def deduction(self):
        if self.used_qty + 1 > self.qty_shipped:
            raise ValidationError(_("The quantity of product is not enough"))
        self.used_qty = self.used_qty + 1

    def return_goods(self):
        if self.qty_shipped <= 0:
            raise ValidationError(_("The quantity of product is not enough"))
        return {
            'name': _('Consignment Returns Allot'),
            'type': 'ir.actions.act_window',
            'res_model': 'consignment.return.wizard',
            'view_mode': 'form',
            'target': 'new',
            'context': {
                'consignment_id': self.id,
                'product_id': self.product_id.id,
            },
        }

    @api.onchange('product_id')
    def _compute_unit_price(self):
        for rec in self:
            rec.unit_price = rec.product_id.list_price
            rec.tax_ids = rec.product_id.taxes_id

    def change_state_done(self):
        for rec in self:
            rec.state = 'done'
            rec.done_date = date.today()

    @api.depends('qty_shipped')
    def _compute_owe_qty(self):
        for rec in self:
            rec.owe_qty = rec.quantity - rec.qty_shipped

    @api.depends('sc_lines', 'sc_lines.state')
    def _compute_qty_shipped(self):
        qty = 0
        for rec in self:
            for line in rec.sc_lines:
                if line.state == 'received':
                    qty += line.quantity
                elif line.state == 'refunded':
                    qty -= line.quantity
            rec.qty_shipped = qty

    @api.depends('account_move_ids', 'account_move_ids.state')
    def _compute_invoiced_qty(self):
        qty = 0
        for rec in self:
            for move in rec.account_move_ids:
                if move.state != 'cancel':
                    for line in move.invoice_line_ids:
                        qty += line.quantity
            rec.invoiced_qty = qty

    def action_confirm(self):
        for rec in self:
            if rec.quantity <= 0:
                raise ValidationError(_("The quantity must be greater than 0"))
            if rec.unit_price <= 0:
                raise ValidationError(_("The unit price must be greater than 0"))
            rec.state = 'confirmed'
            if rec.name == 'Draft':
                rec.name = self.env['ir.sequence'].next_by_code('consignment.sales')

    def add_consignment_sales_line(self):
        return {
            'name': _('Create Consignment Allot'),
            'type': 'ir.actions.act_window',
            'res_model': 'consignment.allot.wizard',
            'view_mode': 'form',
            'target': 'new',
            'context': {
                'consignment_id': self.id,
                'product_id': self.product_id.id,
                'owe_qty': self.owe_qty,
            },
        }

    def action_view_stock_picking(self):
        return {
            'type': 'ir.actions.act_window',
            'name': _('Stock Picking'),
            'res_model': 'stock.picking',
            'view_mode': 'tree,form',
            'domain': [('id', 'in', self.sp_ids.ids)],
            'context': dict(self._context, create=False)
        }

    def action_view_account_move(self):
        return {
            'type': 'ir.actions.act_window',
            'name': _('Account Move'),
            'res_model': 'account.move',
            'view_mode': 'tree,form',
            'domain': [('id', 'in', self.account_move_ids.ids)],
            'context': dict(self._context, create=False)
        }

    def create_invoice(self):
        return {
            'name': _('Create Invoice'),
            'type': 'ir.actions.act_window',
            'res_model': 'consignment.create.invoice.wizard',
            'view_mode': 'form',
            'target': 'new',
            'context': {
                'consignment_id': self.id,
                'product_id': self.product_id.id,
                'customer_id': self.customer_id.id,
                'unit_price': self.unit_price,
                'used_qty': self.used_qty,
                'tax_ids': self.tax_ids.ids,
                'invoiced_qty': self.invoiced_qty,
            },
        }
